Altair Color Scatter Plot on Condition - python

I have this df:
x y term s
0 0.000000 0.132653 matlab 0.893072
1 0.000000 0.142857 matrix 0.905120
2 0.012346 0.153061 laboratory 0.902610
3 0.987654 0.989796 be 0.857932
4 0.938272 0.959184 a 0.861948
The variable s tells us the "distance" of the term from the central line (slope 1).
And I need to make a scatterplot that looks like this:
I have this code so far:
chart = alt.Chart(scatterdata_df).mark_circle().encode(
x = alt.X('x:Q', axis = alt.Axis(tickMinStep = 0.05)),
y = alt.Y('y:Q', axis = alt.Axis(tickMinStep = 0.05)),
color=alt.condition('s:Q', alt.value('red'), alt.value('blue')),
tooltip = ['term']
).properties(
width = 500,
height = 500
)
chart
And that gives me an error.
Javascript Error: Expression parse error: (s:Q)?"red":"blue"
This usually means there's a typo in your chart specification. See the javascript console for the full traceback.
When I just do color = 's' I get this, which is closer:
But again I need that double-gradient of colors. I know that the gradient is respective of the s variable, but I'm not sure how to make it have two gradients, one for each side of the central line.

s:Q is not a valid conditional statement. But, for example, you could write a condition like this:
color = alt.condition(alt.datum.s < 0, alt.value('red'), alt.value('blue'))
and points with s < 0 would be colored red, and all others would be colored blue.
Alternatively, if you want to encode a continuous color scale by the value of s (rather than deciding between two colors based on a condition), you could do
color = 's:Q'
If you'd like to use a color scheme in this case that's different from the default, you can specify it this way:
color = alt.Color('s:Q', scale=alt.Scale(scheme='redblue'))
where the string passed to the scheme argument is one of the built-in named color schemes, listed at https://vega.github.io/vega/docs/schemes/#reference
For more information on customizing colors in Altair, see https://altair-viz.github.io/user_guide/customization.html#customizing-colors

Related

How do I reduce the number of ticks on an Altair graph?

I am using Altair to create a graph, but for some weird reason it's seems to be generating a tick for each of the points. Creating a graph like this Altair Graph
If I filter the dataframe, it produces weird axis values. Altair graph
Is there a way to reduce the amount of ticks? I tried tickCount in the y axis paramater and it didn't work since it seems to require integers.I also tried setting the axis value parameter to a list [0,0.2,0.4,0.6,0.8,1] and that didn't work either. Here is my code (sorry it's so lengthy!). Thank you in advance!
a = alt.Chart(df_filtered).mark_point().encode(x =alt.X('Process_Time_(mins)', axis = alt.Axis(title='Process Time (mins)')),
y = alt.Y('Heavy_Phase_%SS',axis=alt.Axis(title='Heavy Phase %SS', tickCount = 10),sort = 'descending'),
color = alt.Color('DSP_Lot', legend = alt.Legend(title = 'DSP_Lot')),
shape = alt.Shape('Strain', scale = alt.Scale(range = ["circle", "square", "cross", "diamond", "triangle-up", "triangle-down", "triangle-right", "triangle-left"])),
tooltip = [alt.Tooltip('DSP_Lot',title = 'Lot'), alt.Tooltip('Heavy_Phase_%SS', title = 'Heavy Phase %SS'),
alt.Tooltip('Process_Time_(mins)', title = 'Process Time (mins)'), alt.Tooltip('Purpose', title = 'Purpose'), alt.Tooltip('Strain', title = 'Strain'),
alt.Tooltip('Trial', title = 'Trial')]).properties(width = 1000, height = 500)
It's hard to tell without a reproducible example but I suspect the issue is that your y axis is defaulting to a nominal encoding type, in which case you get one tick mark per unique value. If you specify a quantitative type in the Y encoding, it may improve things:
y = alt.Y('Heavy_Phase_%SS:Q', ...)
The reason it defaults to nominal is probably because the associated column in the pandas dataframe has a string type rather than a numerical type.

How to adjust scale ranges in altair?

I'm having trouble getting all of the axes onto the same scale when using altair to make a group of plots like so:
class_list = ['c-CS-m','c-CS-s','c-SC-m','c-SC-s','t-CS-m','t-CS-s','t-SC-m','t-SC-s']
list_of_plots = []
for class_name in class_list:
list_of_plots.append(alt.Chart(data[data['class'] == class_name]).mark_bar().encode(
x = alt.X('DYRK1A', bin = True, scale=alt.Scale()),
y = 'count()').resolve_scale(
y='independent'
))
list_of_plots[0] & list_of_plots[1] | list_of_plots[2] & list_of_plots[3] | list_of_plots[4] & list_of_plots[5] | list_of_plots[6] & list_of_plots[7]
I'd like to have the x axis run from 0.0 to 1.4 and the y axis run from 0 to 120 so that all eight plots I'm producing are on the same scale! I've tried to use domain, inside the currently empty Scale() call but it seems to result in the visualisations that have x axis data from say 0.0 to 0.3 being super squished up and I can't understand why?
For context, I'm trying to plot continuous values for protein expression levels. The 8 plots are for different classes of mice that have been exposed to different conditions. The data is available at this link if that helps: https://archive.ics.uci.edu/ml/datasets/Mice+Protein+Expression
Please let me know if I need to provide some more info in order for you to help me!
First of all, it looks like you're trying to create a wrapped facet chart. Rather than doing that manually with concatenation, it's better to use a wrapped facet encoding.
Second, when you specify resolve_scale(y='independent'), you're specifying that the y-scales should not match between subcharts. If instead you want all scales to be shared, you can use resolve_scale(y='shared'), or equivalently just leave that out, as it is the default.
To specify explicit axis domains, use alt.Scale(domain=[min, max]). Put together, it might look something like this:
alt.Chart(data).mark_bar().encode(
x = alt.X('DYRK1A', bin = True, scale=alt.Scale(domain=[0, 1.4])),
y = alt.Y('count()', scale=alt.Scale(domain=[0, 120]),
facet = alt.Facet('class:N', columns=4),
)

How do the x and y parameters in the Label object work for bokeh?

I've read the documentation for the Label class in Bokeh but the x and y parameters are quite confusing. Their behavior seems to change if you pass something to the x_units and y_units parameters but I don't understand what the units are supposed to be by default.
More specifically, I have a list of strings that I'm using for my x-axis:
xlab = [
'COREPCE2',
'COREPCE3',
'COREPCE4',
'COREPCE5',
'COREPCE6',
'',
'T5YIE'
]
p = figure(..., y_range = (0,.04), x_range = xlab)
If I wanted to draw basically anything else on the plot, I could just use those strings. For example I drew some lines like this:
p.line(['COREPCE2', 'T5YIE'], [.02,.02], color = 'black', line_dash = 'dashed')
p.line(['', ''], [0,.04], color = 'black')
And that works fine, this is the full chart.
Here's the issue though. I want to put a text label on the "COREPCE4" location of the x axis. If I try just passing the string for the x parameter in the Label class it just doesn't work:
section = Label(x = 'COREPCE4', y = .03, text = 'Survey of Professional Forecasters: August 9, 2019')
p.add_layout(section)
It throws an error: ValueError: expected a value of type Real, got COREPCE4 of type str. I don't really know what units its expecting. Is there a way to make Bokeh recognize that I want to use the x-axis label as my x parameter in the same way I've done with the other glyphs?
The propertied x_units, y_units, refer to screen (pixel) vs data-space (axis) units. As of Bokeh 1.3.4 the x and y properties of Label can only be set from floating point numbers, so they cannot be used directly with categorical coordinates. For now you should use LabelSet, even if you are only showing a single label, since it can work with categorical coordinates.

Change color depending on height in Mayavi iso_surface

Is is possible to change the colour of an iso-surface depending on height of the points (in python / mayavi) ?
I can create an iso-surface visualization with my script, but I don't know how to make the iso_surface change colour with z axis so that it will be let's say black at the bottom and white at the top of the plot.
I need this in order to make sense of the visualization when it is viewed from directly above the graph.
If you know any other way to achieve this, please let me know as well.
I only want to show one iso_surface plot.
I managed to do this by combining some code from examples http://docs.enthought.com/mayavi/mayavi/auto/example_atomic_orbital.html#example-atomic-orbital and http://docs.enthought.com/mayavi/mayavi/auto/example_custom_colormap.html . Basically you must create a surface as in atomic-orbital example and then make it change colour depending on x. You must create an array of values for x. My code is (the relevant part) :
#src.image_data.point_data.add_array(np.indices(list(self.data.shape)[self.nx,self.ny,self.nz])[2].T.ravel())
src.image_data.point_data.add_array(np.indices(list(self.data.shape))[0].T.ravel())
src.image_data.point_data.get_array(1).name = 'z'
# Make sure that the dataset is up to date with the different arrays:
src.image_data.point_data.update()
# We select the 'scalar' attribute, ie the norm of Phi
src2 = mlab.pipeline.set_active_attribute(src, point_scalars='scalar')
# Cut isosurfaces of the norm
contour = mlab.pipeline.contour(src2)
# contour.filter.contours=[plotIsoSurfaceContours]
# contour.filter.contours=[plotIsoSurfaceContours[0]]
min_c = min(contour.filter._data_min * 1.05,contour.filter._data_max)
max_c = max(contour.filter._data_max * 0.95,contour.filter._data_min)
plotIsoSurfaceContours = [ max(min(max_c,x),min_c) for x in plotIsoSurfaceContours ]
contour.filter.contours= plotIsoSurfaceContours
# Now we select the 'angle' attribute, ie the phase of Phi
contour2 = mlab.pipeline.set_active_attribute(contour, point_scalars='z')
# And we display the surface. The colormap is the current attribute: the phase.
# mlab.pipeline.surface(contour2, colormap='hsv')
xxx = mlab.pipeline.surface(contour2, colormap='gist_ncar')
colorbar = xxx.module_manager.scalar_lut_manager
colorbar.reverse_lut = True
lut = xxx.module_manager.scalar_lut_manager.lut.table.to_array()
lut[:,-1] = int(plotIsoSurfaceOpacity * 254)
xxx.module_manager.scalar_lut_manager.lut.table = lut
# mlab.colorbar(title='Phase', orientation='vertical', nb_labels=3)
self.data is my data, and for unknown reasons if you want to set opacity of your surface you must reverse the lut first and then set the opacity. Multiplication by 254 instead of 255 is done to avoid a possible bug in mayavi.
I hope this helps someone.

Area Line Plot in Python using Report Lab

I am using Reportlab to create some graphs in my PDF reports. I was creating an Area Line Plot and got stuck at a point where I am not able to understand why am I not getting the output I would like to see.
Here is the code I had written for my output:
def standardLinePlot(data, width=200, height=200):
d = Drawing(width, height)
lp = AreaLinePlot()
lp.data=data
lp.width, lp.height = width, height
lp.xValueAxis.valueMin = 0
lp.xValueAxis.valueMax =36
lp.xValueAxis.valueSteps = [0,6,12,18,24,30,36]
lp.yValueAxis.valueMin = 0
lp.yValueAxis.valueMax =100
lp.strokeColor=colors.black
lp.fillColor=colors.grey
lp.reversePlotOrder = False
lp.joinedLines=1
d.add(lp)
return d
The output I am getting is:
My intended output is that grey color should be in place of red color which is the area under the line plot. The other problem is how can I add the axis title to this chart. For example, I need “Months” to be my X axis and “% of NAV” to be my Y axis.
To define the color for the lines it seems you need to access... well, the lines :). So, lp.lines[0].strokeColor = colors.grey instead of lp.strokeColor = colors.grey, as that one goes for the plot background color!
The question about the labels is a bit more tricky, though... ScatterPlot includes functionality to set labels for X and Y axis, but that's not the case for AreaLinePlot. Of course, you could derive a class from AreaLinePlot copying that functionality, if you're going to use it often.
Change
lp = AreaLinePlot()
to
lp = LinePlot()
and try that
lp.lines[0].strokeColor = colors.red
lp.lines[0].inFill = True
but the fill color will be the same as the line color.
credit goes to #Ricardo Cárdenes

Categories

Resources