Plotting data with arbitrary center and x axis positive in both directions - python-3.x
I’m writing a paper and I have data showing structural changes in my molecule. Those structural changes are inverting the d orbital arrangements.
To show a gradual inversion I’d like to plot a graphic showing the perfect structure (all bonds = 2.1) as the center of my x-axis and to the left what happens to the orbitals if I gradually change two bonds from 2.1 to 2.2. To the right the axis is, also, positive, starting from the center 2.1 and going to 2.2 (but showing what happens with a change to only one bond).
Here is a drawing to clarify my intention:
So far, the best that I could achieve is this:
plt.figure(figsize=(9, 8))
dxy = sns.stripplot(x="Bond", y="Energy(cm-1)", data=dfbd, jitter=False, dodge=False, size=44, marker="_", linewidth=2, hue="Orbital")
plt.ylabel("Energy (Eh)")
If you want to give it a try or have any insights on how to achieve this I'll be extremely grateful.
Here is the data in CSV:
,Type,Bond,Orbital,Energy(cm-1)
0,D4h,2.1,dyz,0.0
1,D4h,2.1,dyz,1.2
2,D4h,2.1,dxz,6.0
3,D4h,2.1,dx2-y2,6473.1
4,D4h,2.1,dz2,6491.1
5,D4h,2.12,dxz,0.0
6,D4h,2.12,dyz,62.9
7,D4h,2.12,dxy,84.3
8,D4h,2.12,dz2,6233.7
9,D4h,2.12,dx2-y2,6560.8
10,D4h,2.14,dxz,0.0
11,D4h,2.14,dyz,125.9
12,D4h,2.14,dxy,171.2
13,D4h,2.14,dz2,5992.8
14,D4h,2.14,dx2-y2,6650.5
15,D4h,2.16,dxz,0.0
16,D4h,2.16,dyz,184.7
17,D4h,2.16,dxy,254.8
18,D4h,2.16,dz2,5761.5
19,D4h,2.16,dx2-y2,6736.9
20,D4h,2.18,dxz,0.0
21,D4h,2.18,dyz,239.4
22,D4h,2.18,dxy,335.4
23,D4h,2.18,dz2,5539.6
24,D4h,2.18,dx2-y2,6820.6
25,D4h,2.2,dxz,0.0
26,D4h,2.2,dyz,290.4
27,D4h,2.2,dxy,413.0
28,D4h,2.2,dz2,5327.0
29,D4h,2.2,dx2-y2,6901.5
30,D4h*,2.1,dyz,0.0
31,D4h*,2.1,dyz,1.2
32,D4h*,2.1,dxz,6.0
33,D4h*,2.1,dx2-y2,6473.1
34,D4h*,2.1,dz2,6491.1
35,D4h*,2.12,dxz,0.0
36,D4h*,2.12,dyz,29.0
37,D4h*,2.12,dxy,39.1
38,D4h*,2.12,dz2,6359.1
39,D4h*,2.12,dx2-y2,6514.3
40,D4h*,2.14,dxz,0.0
41,D4h*,2.14,dyz,60.6
42,D4h*,2.14,dxy,82.5
43,D4h*,2.14,dz2,6239.0
44,D4h*,2.14,dx2-y2,6559.1
45,D4h*,2.16,dxz,0.0
46,D4h*,2.16,dyz,90.0
47,D4h*,2.16,dxy,124.3
48,D4h*,2.16,dz2,6123.8
49,D4h*,2.16,dx2-y2,6602.2
50,D4h*,2.18,dxz,0.0
51,D4h*,2.18,dyz,117.3
52,D4h*,2.18,dxy,164.5
53,D4h*,2.18,dz2,6013.3
54,D4h*,2.18,dx2-y2,6643.9
55,D4h*,2.2,dxz,0.0
56,D4h*,2.2,dyz,142.9
57,D4h*,2.2,dxy,203.2
58,D4h*,2.2,dz2,5907.6
59,D4h*,2.2,dx2-y2,6684.2
Following #ImportanceOfBeingErnest's comment, I would tend to go for the "fake axis" route, as it avoids mucking around with several axes, several labels, legends, etc...
df.loc[:,'fake_Bond'] = df.Bond
df.loc[df.Type=='D4h', 'fake_Bond'] = 2.0 + abs(df.loc[df.Type=='D4h', 'Bond'] - 2.2)
plt.figure(figsize=(9, 8))
dxy = sns.stripplot(x="fake_Bond", y="Energy(cm-1)", data=df, jitter=False, dodge=False, size=44, marker="_", linewidth=2, hue="Orbital")
plt.ylabel("Energy (Eh)")
dxy.set_xticklabels(np.concatenate([np.linspace(2.2,2.1,6),np.linspace(2.12,2.2,5)]))
dxy.set_xlabel("D4h $\longleftarrow$ Bond $\longrightarrow$ D4h*")
Related
Shared axis labels with independent scale
When facet/concat-ing charts, I would like the axis labels to be shared (so only 1 label per column/row, here: Horsepower), but the scale to be independent. Is this possible? I thought a combination of resolve_axis and resolve_scale would be the way to go, as the title is a part of Axis, but I didn't get it to work. I'm also wondering what resolve_axis actually does different than resolve_scale, anyone has an example? base = alt.Chart(source).mark_circle().encode( x=alt.X('Horsepower:Q',), y=alt.Y('Miles_per_Gallon:Q'), color='Origin:N', row=alt.Row('Origin:N'), ).properties( width=200, height=100 ) base.resolve_axis( x='shared' # doesn't do anything obvious ).resolve_scale( x='independent' ) Open the Chart in the Vega Editor
I found a hacky way to do this, by misusing the facet header: base = alt.Chart(source).mark_circle(size=60).encode( x=alt.X('Horsepower:Q',), y=alt.Y('Miles_per_Gallon:Q', axis=alt.Axis(title=''),), color='Origin:N', column=alt.Column('Origin:N', header=alt.Header(title='Miles_per_Gallon')), ).properties( width=200, height=200 ).configure_header( labelExpr="['Origin',datum.value]", titleOrient='left' ) display(base.resolve_scale(y='shared')) display(base.resolve_scale(y='independent'))
I don't know of any way to do what you're hoping for (independent scales with only a single outer axis title) via scale and guide resolution. As to your question of the difference between resolve_scale and resolve_axis, an example may help. Here's a chart with independent y scale: import altair as alt from vega_datasets import data source = data.cars() base = alt.Chart(source).mark_circle().encode( x=alt.X('Horsepower:Q',), y=alt.Y('Miles_per_Gallon:Q'), color='Origin:N', column=alt.Column('Origin:N'), ).properties( width=150, height=150 ) base.resolve_scale( y='independent' ) And here's one with independent y axis: base.resolve_axis( y='independent' ) In both cases, each chart gets its own axis (because independent scales imply independent axes), but only with an independent scale do the axes scales differ from each other.
Ticks on color bar are overlapping because the values are very close to each other
I'm trying to display the exact values on one axis of the color bar and a basic scale on the other. However, some of the exact values are so close together their names overlap on the color bar. Is there a way for me to make the overlapping names appear as a list or just to the side the other values name? I've already tried rotation of the labels, setting vmin/vmax in the color bar method, and setting the ylim's of the second axis. I'm at a lose at what to try next. It feels like this is something matplotlib would allow but I can't find what method or kwargs that allow this manipulation. Many of the commented out tlines are the attempts I've made with help from many posts on StackOverflow. Thank you!! Previous code deleted for clarity UPDATE: Paul H here is a workable example with the same issue I'm trying to fix # Make random data with same issue x, y = np.linspace(-3, 1.5, 20), np.linspace(0, 0.5, 20) # two different ranges used to simulate the same issue in my data fake_phase = np.append(np.random.random_sample(15), np.arange(0.0, .005, 0.001)) fake_labels = np.array(['V439Oph', 'ALVir', 'YZVir', 'XXVir', 'V716Oph', 'BFSer', 'BLHer', 'RXLib', 'CEHer', 'V465Oph', 'V1180Sgr', 'CSCas', 'DQAnd', 'IXCas', 'UYEri', 'TWCap', 'AUPeg', 'MZCyg', 'SWTau', 'TXDel'], dtype=object) # Plot data fig, ax = plt.subplots(1,1,figsize=(15,10)) plt.tight_layout() plt.plot(x, y, marker='.', ms=17, mew=2, linestyle='none') # Make the same colorbar norm = cm.colors.Normalize(vmin=0.0, vmax=1.0, clip=False) cbar = fig.colorbar(cm.ScalarMappable(norm=norm, cmap='rainbow'), ax=ax, extend='both', orientation='vertical', pad=0.005, use_gridspec=True) cbar.set_ticks(fake_phase) cbar.set_ticklabels(fake_labels) cbar.ax.tick_params(which='major', labelsize='large', width=1.5, length=6) cbar.set_label(label='Phase', size='xx-large', labelpad=40) cbar.ax.set_aspect('auto') ax2 = cbar.ax.twinx() pos = cbar.ax.get_position() pos.x0 += 0.1 ax2.set_position(pos) plt.show(); The output of this code: Output of workable example My issue is that the secondary axis on the colorbar (left axis) has values that are so close together their labels overlap. I'm hoping to find a way to space the labels so they are readable. I thought I found a way to accomplish this using axis.set_ticklabels() (set_ticklabels() documentation. In the **kargs section of the doc it references using text properties. In the text properties documentation text properties doc the property 'y' says you can set the y-position of the text. However, when I add this keyword to set_ticklabels() I get an error that the keyword is not recognized.. I've tried adding the property 'y' as a keyword and attribute but I get a keyword error or does not have that attribute error... I'm calling the property wrong but I've never gotten this detailed in editing these parameters. I honestly don't know if this is the best way to solve this, but it's the closest I've gotten so far. I was hoping to use it to offset the labels so they were stacked vertically on top of each other in the same order but far enough apart that the label is readable. Thanks for any input!
how to control transparency of ppp density plot
I am trying to use the layered methods to overlay few spatstat spatial objects. All these objects are for the same window. I have an im layer (density) from a ppp. I want to make this layer a bit transparent in order to have a better visibility of the other objects in the layered object. How can I control the transparency of this density plot (im)? Is there something like alpha or transparency parameter for the plot.im ? UPDATE: library(spatstat) pipes=simplenet plot(pipes) point_net = as.ppp(runifpoint(10, win = Window(pipes))) point_surface = density(point_net) plot(point_surface) layers= layered(point_surface, point_net, pipes) plot(layers) Here , I have plotted 3 layers. As you can see the density plot has very dark blues and reds. Yes, I can plot lines and points with different colours to make them visible, but it would nice to do simple stacked line, point plots and add a little bit of transparency to the density (im) plots. The purpose is just to avoid complex customized plot colours and to explain to colleagues. thank you.
First the commands from the original post: library(spatstat) pipes=simplenet point_net = as.ppp(runifpoint(10, win = Window(pipes))) point_surface = density(point_net) layers= layered(point_surface, point_net, pipes) plot(layers) You need to provide a different colourmap to plot.im. There are two ways you can do this: Plot each layer individually using add = TRUE for subsequent layers and provide the colour map when you plot the im object. Pass a list of plot arguments when you plot the layered object you have created above. I find the first option easier for illustration, so I will do that first. The default colourmap of spatstat is the 29th Kovesi colour sequence (?Kovesi for more details on these sequences): def_col <- Kovesi$values[[29]] head(def_col) #> [1] "#000C7D" "#000D7E" "#000D80" "#000E81" "#000E83" "#000E85" To add transparency you can use to.transparent with your choice of fraction for more/less transparency: def_col_trans <- to.transparent(def_col, fraction = 0.7) head(def_col_trans) #> [1] "#000C7DB3" "#000D7EB3" "#000D80B3" "#000E81B3" "#000E83B3" "#000E85B3" Now you just need to use this as your colourmap: plot(point_surface, col = def_col_trans) plot(point_net, add = TRUE) plot(pipes, add = TRUE) To do it with the layered object you have to make a list of plot argument lists (containing NULL if you don't have additional arguments): layer_args <- list(list(col = def_col_trans), list(NULL), list(NULL)) plot(layers, plotargs = layer_args)
Seaborn heatmap reducing cell size
Is there any way to change cell size of Seaborn heatmap? I found this but I cannot get it work as expected. So, I have long text in y-axis labels. Since all of the texts are chopped off, I would like to shrink cell size of the heatmap much smaller. I don't need that big rectangle. (Highlighted just for example.) (I hid label names.) When I change the figure size by something like, plt.figure(figsize=(8, 6)) or figure.set_size_inches(12, 12) the cell gets bigger as well so the texts remain chopped off. Here is the code. sns.set(font_scale=1.2) ax0 = plt.axes() ax1 = sns.heatmap(hmap, cbar=0, cmap="YlGnBu",linewidths=2, ax=ax0,vmax=3000, vmin=0) ax1.set_title('test heatmap') for item in ax1.get_yticklabels(): item.set_rotation(0) for item in ax1.get_xticklabels(): item.set_rotation(0) figure = plt.gcf() # get current figure figure.set_size_inches(12, 12) plt.savefig('test.png') , dpi=400)
Try using the square=True argument in your sns.heatmap call. This will constrain the heat map cells to a square aspect ratio. ax1 = sns.heatmap(hmap, cbar=0, cmap="YlGnBu",linewidths=2, ax=ax0,vmax=3000, vmin=0, square=True)
You don't actually want to change the cell size but you want to shrink the size of the axes. Ways to to this: use plt.tight_layout() Provide more space to the side e.g. via fig.subplots_adjust(left=0.4) Create an axes, which has the size you want, ax1 = fig.add_axes([0.4,0.2,0.5,0.6]) (where the numbers are [left, bottom, width, height] and use this axes to plot the heatmap, sns.heatmap(... , ax=ax1).
How can I "best fit" an arbitrary cairo (pycairo) path?
It seems like given the information in stroke_extents() and the translate(x, y) and scale(x, y) functions, I should be able to take any arbitrary cairo (I'm using pycairo) path and "best fit" it. In other words, center it and expand it to fill the available space. Before drawing the path, I have scaled the canvas such that the origin is the lower left corner, up is y+, right is x+, and the height and width are both 1. Given these conditions, this code seems to correctly scale the path: # cr is the canvas extents = cr.stroke_extents() x_size = abs(extents[0]) + abs(extents[2]) y_size = abs(extents[1]) + abs(extents[3]) cr.scale(1.0 / x_size, 1.0 / y_size) I cannot for the life of me figure out the translating though. Is there a simpler approach? How can I "best fit" a cairo path on its canvas? Please ask for clarification if anything is unclear in this question.
I have found a solution that I like (at least for my purposes). Just create a new surface and paint the old surface on to the new one.
As for the scale only, I have done a similar thing to adjust an image inside a box with a "best-fit" approach. As about scale, here is the code: available_width = 800 available_height = 600 path_width = 500 figure_height = 700 # formulas width_ratio = float(available_width)/path_width height_ratio = float(available_height)/figure_height scale = min(height_ratio, width_ratio) # result new_path_width = path_width*scale new_figure_height = figure_height*scale print new_path_width, new_figure_height The image gets drawn aligned to the origin (top left in my case), so perhaps a similar thing should be done to translate the path. Also, this best fit is intended to preserve aspect ratio. If you want to stretch the figure, use each of the ratios instead of the 'scale' variable. Hope I have helped