How to fix ugly tick spacing on line chart with small data set

I have some line charts that display a percentage year-over-year. The number of years displayed can vary from one year to ten years. A chart with ten years of data looks fine. A chart with 1 year of data isn’t going to win any awards (it’s just a single point in the middle of the chart), but it’s fine. However, charts with 2 - 4 years of data are ugly, and I cannot seem to figure out a solution. Sample with 2 years of data:

   Year   Grade 3   Grade 4   Grade 5   School Name
0  2021  0.193548  0.071429  0.153846  Sample School
1  2022  0.136364  0.347826  0.142857  Sample School

My code:

color=['#f4979c','#df8f2d','#a4dbdb','#165b65','#b1b134']

cols=[i for i in data.columns if i not in ['School Name','Year']]

fig = px.line(
    data,
    x='Year',
    y=cols,
    markers=True,
    color_discrete_sequence=color,
)

fig.update_traces(mode='markers+lines', hovertemplate=None)
fig.update_layout(
    margin=dict(l=40, r=40, t=40, b=60),
    title_x=0.5,
    font = dict(
        family = 'Open, sans-serif',
        color = 'steelblue',
        size = 10
        ),
    plot_bgcolor='white',
    xaxis = dict(
        title='',
        tickmode = 'array',
        tickvals = data['Year'],
        tickformat="%Y",
        categoryorder = 'array',
        categoryarray = data['Year'],
        mirror=True,
        showline=True,
        linecolor='#b0c4de',
        linewidth=.5,
        gridwidth=.5,
        showgrid=True,
        gridcolor='#b0c4de',
        zeroline=False,
        ),   
    legend=dict(orientation="h"),         
    hovermode='x unified',
    height=400,
    legend_title='',
)

fig.update_yaxes(
    title='',
    mirror=True,
    showline=True,
    linecolor='#b0c4de',
    linewidth=.5,
    gridwidth=.5,
    showgrid=True,
    gridcolor='#b0c4de',
    zeroline=False,
    range=[0, 1],
    dtick=.2,
    tickformat=',.0%',
)

The output:
tmp3

Three years of data is similarly ugly, it simply keeps the outer ticks in the same position and adds a tick in the middle. Ideally, the tick lines would be evenly spaced, in the case above, dividing the chart into equal thirds. Three years of data would result in a chart divided into equal quarters, etc. etc.

It seems like this would be easy to accomplish but I have tried multiple things, pretty much everything I could find on Stack and this website (hours of work), with no success.

What am I missing?

No one has any ideas?I assumed that this would be a simple fix and I was just missing something, but maybe not?

HI @etonblue how do you want it to look like?

You are specifying the tickvalues right here:

What you could do is count the number of years and change your ticks accordingly. Maybe I’m mistunderstanding the issue, though.

1 Like

I’m not exactly sure what you mean. What I’m trying to achieve (sorry for the crappy paint recreation) is something like this:

tmp5

Where the tick lines are closer together instead of right up against the edges. Is there any way to control the layout like this? I suspect I could add additional Axes (2020 and 2023) at the end with no data, but I’d prefer not to do that if possible.

I understand. This is due to the auto range of the x-axis.You could specify the range manually.

I’m not sure I understand. As a test, I added some blank data to my dataframe representing years on either side of the range of years in the dataframe:

tmp6

But this doesn’t look that great either. I’ve tried just about every key variable in in xaxis.layout, including range, and nothing seems to affect the ‘spacing’ of the ticks. Would specifying the range manually address my issue? If so, would you mind giving me an example of specifying the range with a categorical axis (I guess it could be a Date too). Thanks!

Finally found the solution thanks to this post:

Adjusting Space Between Ticks.

Given data[“Year”] as a pd.Series of years in format YYYY, this gives evenly spaced x-axis ticks starting at the left edge and ending at the right edge of the fig.

fig.update_layout(
    xaxis=dict(
        tickvals=data["Year"],
        autorange=False,
        range=[0, len(data["Year"]) - 1],
        tick0=0,
        dtick=1
    ),
)

Small numbers of points on a scatter plot are never going to look great, but this is a pretty good solution imho.

1 Like