Practicing on visualization as a Python newbie I have encountered this conceptual issue that got me thinking,
Infact I managed to change the price format on the y axis of a boxplot , from scientific notation to something more clear. Here the outputs before and after the formatting of the y axis
before
after
boxy=sns.boxplot(x="waterfront", y="price", data=df)
# my experiments success
from matplotlib.ticker import FuncFormatter
f = lambda x, pos: f'{x:.0f}'
boxy.yaxis.set_major_formatter(FuncFormatter(f))
the problem is that I realized that the attribute yaxis should refer to an AXIS object, meanwhile here what i call 'boxy' is an AXES object (at least from the seaborn documentation)
Can anyone explain it?
You're right saying that seaborn boxplot returns a matplotlib Axes object. And referring to this answer, we see Axes and Axis objects are different.
Code inspection isn't needed... but under the hood, seaborn uses matplotlib, it is noted in the GitHub here for boxplots.
when you call sns.boxplot part of drawing your plot creates Axis objects... which are objects of the matplotlib.axis module.
The y axis is in fact the first part of boxy.yaxis.set_major_formatter(FuncFormatter(f))
it is accessed with boxy.yaxis. On which you are calling the function .set_major_formatter(FuncFormatter(f)).
To see this, yaxis = boxy.get_yaxis() will return the yaxis of the boxy axes object.
EDIT IN RESPONSE TO COMMENT:
Again you're correct in the comment that this is not documented from what I could find... but if we look in the matplotlib GitHub here, we see in the YAxis class declaration:
class YAxis(Axis):
__name__ = 'yaxis'
It is just 'YAxis' renamed. Classes will assume their name in the declarative line, unless you re-specify using __name__ which was done here!
It exists!!!
boxy's yaxis inherets the set_major_formatter method from its base class, the 'Axis' class. Just to confirm this hierarchy try looking with method resolution order:
print(type(boxy.get_yaxis()).__mro__)
Should display:
(<class 'matplotlib.axis.YAxis'>, <class 'matplotlib.axis.Axis'>, <class 'matplotlib.artist.Artist'>, <class 'object'>)
I played a bit with Mayavi and particularly with tvtk but I struggle finding examples in which glyphs are placed on the scene at different orientation than default.
Based on this example I prepared the following scene with two cyllinders, one red and one blue,
import mayavi.mlab as mlab
from tvtk.api import tvtk
from tvtk.common import configure_input_data
v = mlab.figure()
# Create two cyllinders
cyl1 = tvtk.CylinderSource(center=(0, 0, 0), radius=1.0, height=0.5, capping=True, resolution=24)
cyl2 = tvtk.CylinderSource(center=(3, 0, 0), radius=1.0, height=0.5, capping=True, resolution=24)
# The mapper converts them into position in 3D
cylinder_mapper1 = tvtk.PolyDataMapper()
configure_input_data(cylinder_mapper1, cyl1.output)
cyl1.update()
cylinder_mapper2 = tvtk.PolyDataMapper()
configure_input_data(cylinder_mapper2, cyl2.output)
cyl2.update()
# Assign them differrent colors
p1 = tvtk.Property(opacity=1.0, color=(1, 0, 0))
p2 = tvtk.Property(opacity=1.0, color=(0, 0, 1))
# The actor is the actually object in the scene.
cyl1_actor = tvtk.Actor(mapper=cylinder_mapper1, property=p1)
v.scene.add_actor(cyl1_actor)
cyl2_actor = tvtk.Actor(mapper=cylinder_mapper2, property=p2)
v.scene.add_actor(cyl2_actor)
# Choose a view angle, and display the figure
mlab.view(90, 45, 7.5, [1.5, 0, 0])
mlab.savefig(filename='cylinders.png')
and what I am trying to achieve here is change the orientation of one of them. Either by providing rotation matrix, either by calling a method, doesn't matter as long as I can somehow rotate the glyph independently (and not just rotate entire scene).
The above example renders
Regarding other questions on that have been previously asked, this one seems useful, yet instead of rotating the actor it rotates entire scene about Y-axis. There also is an example in the scipy-cookbook but again - only with default orientation.
The tvtk documentation is not rich in examples and it is almost hard to believe that there is no example that involves alternate orientation. The documentation only states that classes and methods correspond to their C++ counterparts following some conventions.
tvtk class names are essentially similar to VTK classes except there is no annoying ‘vtk’ at the front. The only difficulty is with classes that start with a digit. For example ‘vtk3DSImporter’ becomes ‘3DSImporter’. This is illegal in Python and therefore the class name used is ‘ThreeDSImporter’. So, if the first character is a digit, it is replaced by an equivalent non-digit string. There are very few classes like this so this is not a big deal.
tvtk method names are enthought style names and not CamelCase. That is, if a VTK method is called AddItem, the equivalent tvtk name is add_item. This is done for the sake of consistency with names used in the enthought package.
Many VTK methods are replaced by handy properties. In the above example, we used m.input = cs.output and p.representation = ‘w’ instead of what would have been m.SetInput(cs.GetOutput()) and p.SetRepresentationToWireframe() etc. Some of these properties are really traits.
Unlike VTK objects, one can set the properties of a tvtk object when the object is initialized by passing the properties (traits) of the object as keyword arguments at the time of class instantiation. For example cs = tvtk.ConeSource(radius=0.1, height=0.5).
Maybe someone who has extensively used VTK with C++ could find that useful but for me it is not very helpful. Nevertheless, I tried to look up the VTK C++ documentation and it did give me some clues. The vtkActor class does inherit some types from vtkProp3D and vtkProp. The vtkProp3D does seem to admit methods and attributes related to object orientation on the scene but it is unclear to me how to set them. The tvtk library is just a wrapper on top of C++ one, which makes it impossible to just inspect what attributes are accepted.
I think for the sake of the internet, maybe we should prepare a proper example of rendering a scene with Mayavi and tvtk that admits both positions of actors and their orientations. Most examples ignore orientations and use spheres so orientation seems not relevant.
Let's summarize.
If someone provides a link to a proper example of rendering a scene with Mayavi and tvtk that involves multiple glyphs with different positions and orientations I will accept such answer.
Making a custom example for (1) will also meet acceptance.
Maybe someone could also comment a bit on the difference between positions of the glyph and the actor that maps this glyph on the scene. As you can see in the examples when I create CylinderSource I explicitly specify where the center is location. This is confusing because is should be the actors center that determines the glyphs position on the scene.
Thanks a lot!
Ok, it turned out Actor accepts orientation argument which is in degrees (not in radians!). Also, the position of the actor has to be specified when actor is created and not when glyph is created!
cyl1_actor = tvtk.Actor(position=(0, 0, 0), mapper=cylinder_mapper1, property=p1, orientation=(0, 0, 90))
renders
I found it by trial and error... The tvtk code in Mayavi package is generated so it is pointless to try to find what attributes are accepted by studying the GitHub repository. Also, you might confuse the tvtk's Actor with Mayavi's Actor which does not have orientation property. Oh and there is actually a property names "property" so try to search for that and get thousands of results as the word property is extensively used everywhere...
Edit:
I noticed I have been specifying positions of actors in the glyph center which was wrong! Here entire source updated:
import mayavi.mlab as mlab
from tvtk.api import tvtk
from tvtk.common import configure_input_data
v = mlab.figure()
# Create two cyllinders
cyl1 = tvtk.CylinderSource(center=(0, 0, 0), radius=1.0, height=0.5, capping=True, resolution=24)
cyl2 = tvtk.CylinderSource(center=(0, 0, 0), radius=1.0, height=0.5, capping=True, resolution=24)
# The mapper converts them into position in 3D
cylinder_mapper1 = tvtk.PolyDataMapper()
configure_input_data(cylinder_mapper1, cyl1.output)
cyl1.update()
cylinder_mapper2 = tvtk.PolyDataMapper()
configure_input_data(cylinder_mapper2, cyl2.output)
cyl2.update()
# Assign them differrent colors
p1 = tvtk.Property(opacity=1.0, color=(1, 0, 0))
p2 = tvtk.Property(opacity=1.0, color=(0, 0, 1))
# The actor is the actually object in the scene.
cyl1_actor = tvtk.Actor(position=(0, 0, 0), mapper=cylinder_mapper1, property=p1)
v.scene.add_actor(cyl1_actor)
cyl2_actor = tvtk.Actor(position=(3, 0, 0), mapper=cylinder_mapper2, property=p2, orientation=(0, 0, 90))
v.scene.add_actor(cyl2_actor)
# Choose a view angle, and display the figure
mlab.view(90, 45, 7.5, [1.5, 0, 0])
mlab.savefig(filename='cylinders.png')
I am using the basic axis.annotate(str(i)) function to show values along the points of my graph. The problem is quite quickly they get to bunched together. So I have two questions: How can I remove an annotation? And how can I make one smaller (font size)?
Here is the reference to the annotation method:
http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.annotate
I have done my research and surprisingly found nothing. Cheers.
axis.annotate(str(i)) returns an axes Annotation object. You need to assign a variable to it and then you manipulate it however you want.
fig, ax = plt.subplots(1,1)
ax.plot(range(5))
text = ax.annotate(xy = (2,2), s='asdf')
# use any set_ function to change all the properties
text.set_fontsize(20)
I want to name figures like this:
import matplotlib as plt
for i in range(0,3):
plt.figure('Method%s',%i)
But seems it is not possible this way.
another way I found is using super title but still it does not work:
from pylab import *
for i in range(0,3):
fig = gcf()
fig.suptitle('Method%s',%i)
do you know any solutions?
If you need to use the figures you are going to create, it may be a good move to store them in some kind of data structure. In my example I will use a list and I will give also an example of using later one of the figures that have been instantiated.
Re naming your figures according to a sequence number, you are correct with the general idea but not with the details, as it happend that in plt.figure() to have a user defined name you have to use a keyword argument that is not named name as one could expect, but … num …
figures = [plt.figure(num="Figure n.%d"%(i+1)) for i in range(3)]
# ^^^
...
figures[1].add_axes(...)
...
I have a GUI built using PyQt4 where I use matplotlib (FigureCanvas) to plot several plots using multiple canvases (this is intentional rather than using subplots). for each canvas I use method:
self.canvas_xx.mpl_connect('scroll_event', self.on_mouse_scroll)
where xx represents the iteration of the canvas to get a signal to perform some action. I want to be able to reference the canvas by its name rather than using:
ylabel = event.inaxes.axes.get_ylabel().split(' ')[0]
where I use the longer method of referncing the ylabel name of each graph.
I looked under the event method using: dir(event) and there is a method called "canvas", but there is no apparent method to get the name of the canvas.
Any ideas?
I am not quite sure what you mean by name, but you can get a a reference to the canvas object via
event_canvas = event.inaxes.axes.figure.canvas
and canvas events are hashable, so you can use them as keys in a dict
other_thing = pre_populated_dict[event_canvas]
to keep track of what ever other data you want to about a given canvas in your code.
In python there is, in general, not a clean way to get the names of references to an object (it can be done, but you shouldn't).