I am trying to make a basic line & point plot in Bokeh (0.12.3) using the following code. I have set the x_axis_type as 'datetime' and I am plotting a (random) variable vs. a pandas (0.19.0) datetime64 dtype that is the index of the dataframe (i.e. a timeseries).
The problem I see with the plot is that the dates are not properly aligned. In the time series, the max date is 2016-11-06, however, the last scale tick is for Nov 16, and there is a point aligned to what appears to be several days after that.
Curiously, when zooming in the plot, the alignment looks correct!
Is this a bug, or am I doing something wrong for this plot? Do I need to be more specific in how the x-axis should be rendered?
Also, I really think the scale increments should be in equal number of days. However in this case, Bokeh plots the scale increments to be on the same day of esch month (which is a varying number of days increments). I have seen this before in other plots, and that default can hamper interpretation.
Appreciate any help on this. Here is the code and the screen shots that demonstrate the issue:
# imports & config
import pandas as pd
import numpy as np
from bokeh.plotting import figure, show, output_notebook
output_notebook()
# create a times series dataframe
rng = pd.date_range('2016-07-24', periods=16, freq='W')
df = pd.DataFrame(np.random.randn(len(rng)), index = rng, columns=['Y'])
# view the tail of the data to compare to plot
df.tail()
# make and render the plot
p1 = figure(x_axis_type='datetime',
title='Y vs Week Ending',
plot_width=700, plot_height=400)
p1.xaxis.axis_label = 'Week Ending'
p1.yaxis.axis_label = 'Y'
p1.line(df.index, df['Y'])
p1.circle(df.index, df['Y'])
p1.yaxis.minor_tick_line_alpha=0
show(p1)
the last scale tick is for Nov 16, and there is a point aligned to what appears to be several days after that.
That tick is for Nov 2016.. it's not very intuitive, but the year is contracted into the label.
Knowing this may change your perspective w.r.t. this comment:
...I really think the scale increments should be in equal number of days. However in this case, Bokeh plots the scale increments to be on the same day of [each] month...
What it's done is change the base unit from day to month, which is probably the more correct approach.
Related
I have a 3D camera that could give Matlab information about the distance of an object in real time after the command distance=function1(Device)(I have omit this function since it is not important here).
I would like to make a program that shows the object moving when time changes.
I have already succeeded in using:
t1=clock;
while......(in a loop)
distance(i)=step(Device);
t2=clock;
times(i)=etime(t2,t1);
plot(times,distance);
end
to show the object moving. However, the X axis in this figure is the comparative time, which means the x axis begins with 0 seconds and ends with (t2-t1) seconds .
Now I try to find a way to change the X axis to the absolute time or the cpu time.
Like the following picture:
I'd like to change the comparative time(in black fonts) to the absolute system time (in red fonts).
I have try ' datetick' but it doesn't work properly?
Is there any way to do this?
The following creates a string out of the clock, plots distance, then attempts to change the labels based on the text strings each iteration. I tested a simple instance of it in MATLAB.
while ... (in a loop)
distance(i)=step(Device);
t2=clock;
tint = int8(t2(4:6)))
stamp{i} = strcat(int2str(tint(1)),':',int2str(tint(2)),':',int2str(tint(3)))
plot(distance)
set(gca,'XTick',1:i,'XTickLabel',stamp)
end
As far as getting the AM and PM to show, well, you'll have to do some extra witchcraft but it should be possible, based on the clock values. Then just append AM or PM into the stamp{i} assignation.
Hint, if t2(4) > 12 you are looking at PM. Else, AM.
One limitation with this is that the more iterations you do, the more crowded your X-Axis is going to become.
I am using seaborn to create a boxplot. When I specify a column by which to group/color the boxes, the width of the boxes becomes so narrow that they are hard to see. The only change I am making is specifying an argument for hue, which points to a column in the dataframe passed. I have tried using the 'width' parameter (as mentioned here), which does increase the width of the boxplots, but also the distance at which they are spread apart.
Help: How can I maintain the width of the boxes while specifying a hue parameter?
I will show my code and results below:
My dataframe:
Out[3]:
timestamp room_number floor floor_room temperature
0 2016-01-19 09:00:00-05:00 11a06 11 11_11a06 23.0
1 2016-01-19 09:00:00-05:00 east-inner 11 11_east-inner 22.8
2 2016-01-19 09:00:00-05:00 east-window 11 11_east-window 22.9
Use of seaborn with odd boxplot widths, using a grouping factor:
sns.boxplot(x=xunit, y=var, data=df, order=order, hue='floor')
Use of seaborn that has reasonable boxplot widths, but no grouping factor:
sns.boxplot(x=xunit, y=var, data=df)
In version 0.8 (July 2017), the dodge parameter was added
to boxplot, violinplot, and barplot to allow use of hue without changing the position or width of the plot elements, as when the hue varible is not nested within the main categorical variable.
(release notes v0.8.0)
Your code would look like this:
sns.boxplot(x=xunit, y=var, data=df, order=order, hue='floor', dodge=False)
It turns out the the 'hue' parameter causes the issue (I am not sure why). By removing this parameter/argument from the function, the problem goes away, but you must provide extra information so that the boxplots are color coded by the condition desired. The following line of code fixed my problem:
sns.boxplot(x=xunit, y=var, data=df, order=order,palette=df[condition_column].map(palette_dir))
Where palette_dir is a dictionary of colors for each condition, mapped to a column of data.
The boxplots look normal now, but I am struggling to add a figure legend. I am hoping the person who resolved this in this post can point me to their method.
I have created a chart with 2 axes that acts as a panel chart (see image)
As a panel chart I only want to show the portions of the relevant y-axes to the chart next to them. For example, for the right-most y-axis I used a custom number format to exclude anything less than 0:
_(* #,##0_);_("";_(* 0??_);_(#_)
But for the left most y-axis, I'm stuck. I want to show -400 to positive 400. I've tried 2 different options, but neither is producing the desired effect.
[<0](#,##0);[>500000000]"";#,##0_)
[<0](#,##0);[<500000000]#,##0_);""
Here is the result I'm looking for:
I learned something new today (and a bit weird) regarding formats and chart axes
After some experimenting, this is what I ended up using:
[White][>500]_(#,##0_);(#,##0);0;
The odd part: When you change the Display Units of the axis (for me, millions), then the formatting no longer recognizes the original amount (500,000,000).
Once I figured that out, I was able to work out the solution.
I have this column chart that has 2 modes, monthly visualization and yearly visualization, the monthly visualization works just fine with many column, however, my yearly visualization is broken because i can't get the only column that appears to be on the center of the chart, it's always being set to the first point on my XAxis.
If I were using a NumberAxis it would be easy to solve, just set the column to the middle point (in this case, position 6 among the total of 12 months). However I'm using CategoryAxis, since it isn't ordered as NumberAxis is, I'm unable to use the same solution....
How can I achieve this result with a CategoryAxis ?
PS: No matter the SChartRange I set to this Axis, the column will always be set to the first position in the XAxis.
Found a way to achieve the result I wanted.
I've altered the range to be around the first dataPoint only, this way the column got placed in the middle of the chart without having to be the "middle dataPoint", being the ONLY dataPoint. The code goes into my sChart: dataPointAtIndex forSeriesAtIndex as follows
-(id<SChartData>)sChart:(ShinobiChart *)chart dataPointAtIndex:(int)dataIndex forSeriesAtIndex:(int)seriesIndex{
.
.
.
SChartNumberRange * numberRange;
if(isYearlyChart){
numberRange = [[SChartNumberRange alloc] initWithMinimum:[NSNumber numberWithFloat:-0.9]andMaximum:[NSNumber numberWithInt:(1)]];
}
The normal NumberRange I was using was from 1 through 13.
Hope this helps others with similar problems regarding this subject :)
PS: I'll mark this as the correct answer as soon as possible.
i'm using the Line Chart component to generate a chart based on the consumption of a building.
Imagine a possible chart based on the consumption of a building in a period of a month and a resolution of a day. It will have 30 points of consumption corresponding to 30 days.
The problem is with the category axis labels. With a considerable amount of points, the labels becomes unreadable. How can i just label some points?
My best regards
Don't use a "Line" chart. Instead use a "Time Series" chart.
It automatically handles the issues around charting all points but only labeling a readable number of them. It also handles problems created by data points that are not uniformly spaced.
EDIT: If your incoming data is a String instead of a Date, then you have extra work. Time Series charts expect Times (well, Dates). You'll need to cast your DateString into a real Date. But the work is small, and the benefits are large. Use a variable like this: new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse($F{MyDateString}).
Use this code to generate a label on the line chart in JASPER report
else if(jasperChart.getChartType() == JRChart.CHART_TYPE_LINE) {
LineAndShapeRenderer line = (LineAndShapeRenderer) chart.getCategoryPlot().getRenderer();
line.setBaseItemLabelsVisible(Boolean.TRUE);
line.setBaseItemLabelGenerator((CategoryItemLabelGenerator) new StandardCategoryItemLabelGenerator());
}